package com.cnap.controller;

import com.cnap.model.common.CommonResult;
import com.cnap.model.common.PageResult;
import com.cnap.model.log.OperationTypeEnum;
import com.cnap.model.progress.ProgressVOForSplit;
import com.cnap.model.schedule.DistributeParam;
import com.cnap.model.schedule.MicroServiceVO;
import com.cnap.model.schedule.OperateParam;
import com.cnap.model.schedule.OperateTypeEnum;
import com.cnap.model.schedule.QueryMicroServiceParam;
import com.cnap.model.schedule.ScaleStrategyDTO;
import com.cnap.model.schedule.StrategyDTO;
import com.cnap.model.schedule.UpdateUserChooseParam;
import com.cnap.model.schedule.ValidateParam;
import com.cnap.service.MicroSvcService;
import com.cnap.service.OperateService;
import com.cnap.service.OperationLogService;
import com.cnap.service.ProgressService;
import com.cnap.service.ScheduleService;
import com.cnap.utils.TokenUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 微服务策略部署控制类
 *
 * @author xc
 **/
@Api(tags = "策略部署")
@RestController
@RequestMapping("/api/micro-service")
public class MicroServiceController {

    /*
    微服务分解
    调度策略配置
    扩缩容策略配置
    微服务分布式部署前的准备工作。
     */

    private static final Logger LOGGER = LoggerFactory.getLogger(MicroServiceController.class);

    private final MicroSvcService microSvcService;
    private final ProgressService progressService;
    private final OperationLogService operationLogService;
    private final ScheduleService scheduleService;
    private final OperateService operateService;

    @Autowired
    public MicroServiceController(MicroSvcService microSvcService, ProgressService progressService, OperationLogService operationLogService
            , ScheduleService scheduleService, OperateService operateService) {
        this.microSvcService = microSvcService;
        this.progressService = progressService;
        this.operationLogService = operationLogService;
        this.scheduleService = scheduleService;
        this.operateService = operateService;
    }

    /**
     * 查询微服务
     *
     * @param queryMicroServiceParam 查询参数
     * @return 结果
     */
    @ApiOperation(value = "查询微服务", notes = "查询微服务", httpMethod = "POST")
    @PostMapping("/list")
    public CommonResult<PageResult<MicroServiceVO>> listMicroService(@RequestBody QueryMicroServiceParam queryMicroServiceParam) {
        PageResult<MicroServiceVO> result = microSvcService.findByPage(queryMicroServiceParam);
        return CommonResult.success(result);
    }

    /**
     * 分解微服务
     *
     * @param applicationId 应用id
     * @return 结果
     */
    @ApiOperation(value = "分解微服务", notes = "分解微服务", httpMethod = "GET")
    @GetMapping("/split/{applicationId}")
    public CommonResult<String> splitMicroServices(@PathVariable("applicationId") String applicationId) {
        LOGGER.info("[micro-service]: split micro service, applicationId={}", applicationId);
        microSvcService.splitMicroServices(applicationId);
        String message = TokenUtils.getUserName() + "分解了应用";
        operationLogService.saveOperationLog(OperationTypeEnum.OTHER.getType(), message);

        return CommonResult.success("");
    }

    /**
     * 查询进度
     *
     * @param applicationId 应用id
     * @return 结果
     */
    @ApiOperation(value = "查询进度", notes = "查询进度", httpMethod = "GET")
    @GetMapping("/progress/{id}")
    public CommonResult<ProgressVOForSplit> queryProgressForSvc(@PathVariable("id") String applicationId) {
        ProgressVOForSplit progressVO = progressService.getProgressForSplitByApplicationId(applicationId);

        return CommonResult.success(progressVO);
    }

    /**
     * 添加调度策略
     *
     * @param strategyDTOs 策略信息
     * @return 结果
     */
    @ApiOperation(value = "添加调度策略", notes = "添加调度策略", httpMethod = "POST")
    @PostMapping("/strategy/schedule/add")
    public CommonResult<String> addScheduleStrategyToMicroServices(@Validated @RequestBody List<StrategyDTO> strategyDTOs) {
        LOGGER.info("[micro-service]: add schedule policy for service ids={}",
                strategyDTOs.stream().map(StrategyDTO::getServiceId).collect(Collectors.toList()));
        scheduleService.addScheduleStrategy(strategyDTOs);
        String message = TokenUtils.getUserName() + "添加了调度策略";
        operationLogService.saveOperationLog(OperationTypeEnum.ADD.getType(), message);

        return CommonResult.success("success");
    }


    /**
     * 添加扩缩容策略
     *
     * @param strategyDTOS 策略参数
     * @return 结果
     */
    @ApiOperation(value = "添加扩缩容策略", notes = "添加扩缩容策略", httpMethod = "POST")
    @PostMapping("/strategy/scale/add")
    public CommonResult<String> addScaleStrategyToMicroServices(@Validated @RequestBody List<ScaleStrategyDTO> strategyDTOS) {
        LOGGER.info("[micro-service]: add schedule policy for service ids={}",
                strategyDTOS.stream().map(ScaleStrategyDTO::getServiceId).collect(Collectors.toList()));
        scheduleService.addScaleStrategy(strategyDTOS);
        String message = TokenUtils.getUserName() + "添加了扩缩容策略";
        operationLogService.saveOperationLog(OperationTypeEnum.ADD.getType(), message);
        return CommonResult.success("");
    }

    /**
     * 根据id列表删除策略
     *
     * @param strategyIds 策略id列表
     * @return 结果
     */
    @ApiOperation(value = "删除策略", notes = "删除策略", httpMethod = "POST")
    @PostMapping("/strategy/delete")
    public CommonResult<String> deleteStrategyByIds(@RequestBody List<String> strategyIds) {
        LOGGER.info("[micro-service]: delete strategys ids={}", strategyIds);
        boolean result = scheduleService.deleteStrategyByIds(strategyIds);

        String message = TokenUtils.getUserName() + "删除了策略";
        operationLogService.saveOperationLog(OperationTypeEnum.DELETE.getType(), message);
        return result ? CommonResult.success("success") : CommonResult.failed("fail");
    }

    /**
     * 根据微服务id获取yaml
     *
     * @param serviceId 微服务id
     * @return 结果
     */
    @ApiOperation(value = "根据id查询yaml", notes = "根据id查询yaml", httpMethod = "GET")
    @GetMapping("/yaml/{id}")
    public CommonResult<String> getYamlByServiceId(@PathVariable("id") String serviceId) {
        LOGGER.info("[micro-service]: get yaml with service id={}", serviceId);
        String yaml = microSvcService.getYamlByServiceId(serviceId);
        return CommonResult.success(yaml);
    }

    /**
     * 验证
     *
     * @param validateParam 验证参数
     * @return 结果
     */
    @ApiOperation(value = "验证", notes = "验证", httpMethod = "POST")
    @PostMapping("/validate")
    public CommonResult<String> validate(@RequestBody ValidateParam validateParam) {
        LOGGER.info("[micro-service]: validate micro service id={}, clusters={}", validateParam.getServiceId(),
                validateParam.getClusters());
        boolean validateResult = microSvcService.validate(validateParam);

        return validateResult ? CommonResult.success("success") : CommonResult.failed("fail");
    }

    /**
     * 根据应用id查询微服务信息
     *
     * @param applicationId 应用id
     * @return 结果
     */
    @ApiOperation(value = "根据id查询微服务", notes = "根据id查询微服务", httpMethod = "GET")
    @GetMapping("/list/{appId}")
    public CommonResult<List<MicroServiceVO>> getMicroServicesByApplicationId(@PathVariable("appId") String applicationId) {
        LOGGER.info("[micro-service]: query micro service by appId={}", applicationId);
        List<MicroServiceVO> microServiceVOS = microSvcService.selectMicroServicesByAppId(applicationId);
        return CommonResult.success(microServiceVOS);
    }

    /**
     * 部署
     *
     * @param distributeParam 部署参数
     * @return 结果
     */
    @ApiOperation(value = "部署", notes = "部署", httpMethod = "POST")
    @PostMapping("/distribute")
    public CommonResult<String> distribute(@Validated @RequestBody DistributeParam distributeParam) {
        LOGGER.info("[micro-service]: distribute service id={} to clusters={}", distributeParam.getServiceId(),
                distributeParam.getClusters());
        boolean result = microSvcService.distribute(distributeParam);

        String message = TokenUtils.getUserName() + "部署了微服务";
        operationLogService.saveOperationLog(OperationTypeEnum.ADD.getType(), message);

        return result ? CommonResult.success("success") : CommonResult.failed("fail");
    }

    /**
     * 操作（暂停，恢复）
     *
     * @param operateParam 操作参数
     * @return 结果
     */
    @ApiOperation(value = "操作", notes = "操作", httpMethod = "POST")
    @PostMapping("/operation")
    public CommonResult<String> operation(@Validated @RequestBody OperateParam operateParam) {
        LOGGER.info("[micro-service]: operate service, {}", operateParam);
        boolean result = operateService.operate(operateParam);

        String message = TokenUtils.getUserName() + OperateTypeEnum.getOperateTypeFromType(operateParam.getOperationType())
                .getMessage() + "了微服务";
        if (OperateTypeEnum.DELETE.getMessage().equals(operateParam.getOperationType())) {
            operationLogService.saveOperationLog(OperationTypeEnum.DELETE.getType(), message);
        } else {
            operationLogService.saveOperationLog(OperationTypeEnum.OTHER.getType(), message);
        }

        return result ? CommonResult.success("success") : CommonResult.failed("fail");
    }

    @ApiOperation(value = "更新用户选择", notes = "更新用户选择", httpMethod = "POST")
    @PostMapping("/update/user-choose")
    public CommonResult<String> updateUserChooseCloud(@RequestBody UpdateUserChooseParam updateUserChooseParam) {
        LOGGER.info("[micro-service]: update user choose cloud, {}", updateUserChooseParam);
        microSvcService.updateUserChooseCloud(updateUserChooseParam);
        return CommonResult.success("success");
    }
}
